/**
 * Copyright 2011 AJG van Schie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.googlecode.julius.gui;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.SnapshotParameters;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.Axis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.image.Image;
import javafx.stage.FileChooser;

import javax.imageio.ImageIO;

import julius.utilities.CollectionHelper;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;

import com.googlecode.julius.controller.ControllerApi.DayEntry;
import com.googlecode.julius.controller.ControllerApi.Sprint;
import com.googlecode.julius.data.Status;
import com.googlecode.julius.utils.DateHelper;

/**
 * 
 * @author AJG van Schie
 * @author Yosuf Haydary
 */
public class BurnDownChart {
    private static final String SYSPROP_SCRUMVIZ_PROJECT_NAME = "scrumviz.project.name";
	private static final String SYSPROP_SCRUMVIZ_USER_DIR = "scrumviz.user.dir";
	private static final String CHARTS_DIR = "charts";
	public static Logger log = Logger.getLogger(BurnDownChart.class);
    private static String PNG_FORMAT_EXTENTION = "png";

    private final AreaChart<String, Number> areaChart;
    private final Axis<String> xAxis;
    private final NumberAxis yAxis;
    private final Map<Status, XYChart.Series<String, Number>> series = CollectionHelper.map();

    public BurnDownChart(final AreaChart<String, Number> areaChart, final Axis<String> xAxis, final NumberAxis yAxis) {
        super();
        this.areaChart = areaChart;
        this.xAxis = xAxis;
        this.yAxis = yAxis;
    }

    public void render(final Sprint sprint, final Collection<DayEntry> dayEntries) {
        areaChart.setTitle(sprint.toString());

        initSeries();

        for (DayEntry day : dayEntries) {
            for (Status state : Status.values()) {
                Double hours = day.hours(state);
                String label = format(day.day());
                if (hours != null) { // we want a hard cut at the last real value, not a dive to 0
                    XYChart.Data<String, Number> item = new XYChart.Data<String, Number>(label, hours);
                    series.get(state).getData().add(item);
                }
            }
        }

        initXAxis();
        initYAxis();
    }

    private void initSeries() {
        areaChart.getData().clear();
        for (Status s : Status.values()) {
            XYChart.Series<String, Number> serie = new XYChart.Series<String, Number>();
            serie.setName(s.toString());
            series.put(s, serie);
            areaChart.getData().add(serie);
        }

    }

    protected void initXAxis() {
        xAxis.setLabel("State");
    }

    protected void initYAxis() {
        yAxis.setLowerBound(200);
        yAxis.setUpperBound(0);
        yAxis.setTickUnit(10);
    }

    public String format(final LocalDate date) {
        return DateHelper.friendly(date);
    }

    public void print() {
        Platform.runLater(new Runnable() {

            @Override
            public void run() {
            	
            	File file = determineFileToSave(PNG_FORMAT_EXTENTION);
            	
            	if(file != null) {
	                Image image = areaChart.snapshot(new SnapshotParameters(), null);
	                log.info("snapshot image created");
	
	                try {
	                    ImageIO.write(SwingFXUtils.fromFXImage(image, null), PNG_FORMAT_EXTENTION, new File(file.getPath()));
	                
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	
	            }
            }
        });
    }
    
	/**
	 * Tries to setup a file in the scrumviz user directory. 
	 * If the scrumviz user dir is not set, it will be routed to choose manually.
	 * 
	 * @param extention
	 * @return
	 */
	private File determineFileToSave(String extention) {
		String scrumvizDir = System.getProperty(SYSPROP_SCRUMVIZ_USER_DIR);
		
		if(scrumvizDir == null || !new File(scrumvizDir).exists()){
			 log.info("Invalid or unexisting scrumviz user directory (-D"+ SYSPROP_SCRUMVIZ_USER_DIR + "). Routing to manual choice.");
			 return chooseFile(extention);
		}
		
		String fileName = new DateTime().toString("yyyy-MM-dd_HHmm") + "_" + getProjectName() + "." +extention;
		File file = new File(scrumvizDir+ File.separator + fileName);
		
		return file;
	}
	
	private String getProjectName() {
		String projectName = System.getProperty(SYSPROP_SCRUMVIZ_PROJECT_NAME);
		
		if(projectName == null){
			log.info("No scrum project name (-D"+SYSPROP_SCRUMVIZ_PROJECT_NAME+") set. Using \"unset-project-name\" instead.");			
			return "unset-project-name";
		}
		return projectName;
	}
	
	private File chooseFile(String extention) {
		FileChooser.ExtensionFilter filter = new FileChooser.ExtensionFilter(extention+ " files (*." +
				extention+")", "*."+extention);
		
		FileChooser chooser = new FileChooser();
		chooser.getExtensionFilters().add(filter);
		File file = chooser.showSaveDialog(null);
		return file;
	}
}
